Skip to content

USE 557 - Parallelized input record read and bitstream download#10

Merged
ghukill merged 3 commits into
mainfrom
USE-557-cli-harvest-orchestration
May 18, 2026
Merged

USE 557 - Parallelized input record read and bitstream download#10
ghukill merged 3 commits into
mainfrom
USE-557-cli-harvest-orchestration

Conversation

@ghukill

@ghukill ghukill commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Purpose and background context

Why these changes are being introduced:

A primary flow in this app is reading input records from TIMDEX (currently hardcoded to filter to theses records) downloading fulltext for them, and then writing back to the TIMDEX dataset. The writing back is not yet established, so for now we write to JSONLines as debugging output. But the rest of the business logic is ready to be built, building on the CLI scaffolding.

Parallelization is important. If a single item takes 1 second, for ~150k items in DSpace that's ~41 hours. Not realistic. With parallelization of ~20 workers, and retries and backoffs to ensure we don't get rate limited at the DSpace boundary, seeing more like ~33 records per second, which works out to ~1 hour. It's likely that an agressive run could bump --workers=50 (or even higher) and ramp this up. The primary bottleneck is network I/O, making this a good fit for threads.

How this addresses that need:

Introduces new dfh/harvest.py file that encapsulates parallelized reading of TIMDEX records, generation of pre-signed URLs from DSpace, and actual bitstream downloads from S3. This parallelization has sensible defaults, but is configurable via some limited CLI arguments (e.g. --workers).

The parallelization lumps the generation of URLs and downloading of content into a single method with retries. This allows the parallelization to be relatively simple, and leave retries to the method.

Ultimately, an iterator of record metadata + fulltext is yielded, which is what we'll need to write back to TIMDEX dataset.

NOTE: DSpace credential parsing is still assuming env vars are set for host, username, and password. It's likely that we'll parse an env var with JSON credentials; this is not yet implemented.

How can a reviewer manually see the effects of these changes?

1- Set TimdexMangers Dev1 credentials

2- Set env vars (DSpace credentials shared offline of PR):

TDA_LOG_LEVEL=DEBUG
WARNING_ONLY_LOGGERS=asyncio,botocore,urllib3,s3transfer,boto3,MARKDOWN

DSPACE_API_BASE="..."
DSPACE_USERNAME="..."
DSPACE_PASSWORD="..."

TIMDEX_DATASET_LOCATION=s3://timdex-extract-dev-222053980223/dataset

3- Run CLI:

uv run --env-file .env dfh --verbose \
harvest \
--record-limit=100 \
--workers=5 \
--output-jsonl=output/use557.jsonl

Includes new or updated dependencies?

YES

Changes expectations for external applications?

NO

What are the relevant tickets?

Code review

  • Code review best practices are documented here and you are encouraged to have a constructive dialogue with your reviewers about their preferences and expectations.

Why these changes are being introduced:

A primary flow in this app is reading input records from TIMDEX, currently
filtered to theses records, downloading fulltext for them, and then writing back
to the TIMDEX dataset.  The writing back is not yet established, so for now we write
to JSONLines as debugging output.  But the rest of the business logic is ready to be
built, building on the CLI scaffolding.

Parallelization is important.  If a single item takes 1 second, for ~150k items in
DSpace that's ~41 hours.  Not realistic.  With parallelization of ~20 workers, and
retries and backoffs to ensure we don't get rate limited at the DSpace boundary,
seeing more like ~33 records per second, which works out to ~1 hour.  It's likely
that an agressive run could bump `--workers=50` (or even higher) and ramp this up.

How this addresses that need:

Introduces new `dfh/harvest.py` file encapsulates parallelized reading of TIMDEX
records, generation of pre-signed URLs from DSpace, and actual bitstream downloads
from S3.  This parallelization has sensible defaults, but is configureable via
some limited CLI arguments (e.g. `--workers`).

The parallelization lumps the generation of URLs and downloading of content into
a single method with retries.  This allows the parallelization to be relatively
simple, and leave retries to the method.

Ultimately, an iterator of record metadata + fulltext is yielded, which is what
we'll need to write back to TIMDEX dataset.

NOTE: DSpace credential parsing is still assuming env vars are set for host,
username, and password.  It's likely that we'll parse an env var with JSON
credentials; this is not yet implemented.

Side effects of this change:
* None

Relevant ticket(s):
* https://mitlibraries.atlassian.net/browse/USE-557
@ghukill ghukill changed the title Parallelized input record read and bitstream download USE 557 - Parallelized input record read and bitstream download May 18, 2026
Why these changes are being introduced:

Intermittent failures were observed for authentication against a cold API endpoint,
where after a successful authentication, all future requests were healthy.  Could be
an artifact of server deploys and upgrades (this codebase is landing during a DSpace
migration), or an artifact of DSpace CRIS, unsure.  Either way, this authentication
check + retry feels pretty harmless to layer on until we're 100% sure it's not needed.

How this addresses that need:

* Adds new `warm_dspace_auth()` function
* Applied at CLI level for `harvest` command before real API work

Side effects of this change:
* A cold DSpace API, when given some retries to authenticate, is successful
after that.

Relevant ticket(s):
* https://mitlibraries.atlassian.net/browse/USE-557
@ghukill ghukill force-pushed the USE-557-cli-harvest-orchestration branch from 3419d5a to dcb11b6 Compare May 18, 2026 13:22
@ghukill ghukill changed the base branch from USE-557-record-read-and-harvest to main May 18, 2026 13:22
@ghukill ghukill marked this pull request as ready for review May 18, 2026 14:16
@ghukill ghukill requested a review from a team as a code owner May 18, 2026 14:16

@ehanson8 ehanson8 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from fixing our favorite typo, looks great!

Comment thread dfh/dspace.py
Comment thread dfh/harvest.py
Comment thread dfh/harvest.py Outdated
Comment on lines +123 to +124
"fulltext_bistream_uuid": bitstream_uuid,
"fulltext_bistream_content": fulltext,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's back.....bistream 🙂

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK. Now, not just a comment or docstring....

Good catch, thank you! I'm going to add a keystroke logger on my machine that shocks me anytime I accidentally type "bistream"

@ghukill ghukill merged commit 7deef4b into main May 18, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants